package com.lyfei.yd.service;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lyfei.yd.common.exception.CustomException;
import com.lyfei.yd.domain.entity.SpecKeyValue;
import com.lyfei.yd.domain.entity.Spu;
import com.lyfei.yd.domain.dto.PageQueryDto;
import com.lyfei.yd.domain.dto.SkuDto;
import com.lyfei.yd.domain.dto.SkuSelector;
import com.lyfei.yd.domain.entity.Sku;
import com.lyfei.yd.domain.entity.SkuSpec;
import com.lyfei.yd.domain.vo.SkuVo;
import com.lyfei.yd.mapper.SkuMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service("skuService")
public class SkuService extends BaseService<SkuMapper, Sku>{

    @Autowired
    private SpuService spuService;

    @Autowired
    private SpecValueService specValueService;

    @Autowired
    private SkuSpecService skuSpecService;

    public IPage<SkuVo> page(PageQueryDto dto) {
        IPage<Sku> skuPage = this.page(new Page<>(dto.getCurrent(), dto.getPageSize()),
                new QueryWrapper<Sku>().orderByDesc("update_time"));


        // 转换成vo
        return skuPage.convert(this::toVo);
    }

    public SkuVo getSkuDetail(Long id) {
        Sku sku = this.getById(id);

        return toVo(sku);
    }

    @Transactional
    public void create(SkuDto dto) {
        int count = this.count(new LambdaQueryWrapper<Sku>()
                .eq(Sku::getTitle, dto.getTitle()));
        if(count > 0) {
            throw new CustomException("Sku标题重复");
        }

        Spu spu = spuService.getById(dto.getSpuId());
        if(spu == null) {
            throw new CustomException("商品不存在");
        }

        List<SkuSelector> selectors = dto.getSelectors();
        List<SpecKeyValue> specs = this.checkSelectors(selectors);
        if(specs == null) {
            throw new CustomException("规格选择错误");
        }

        Sku sku = new Sku();
        BeanUtils.copyProperties(dto, sku);
        sku.setCreateTime(new Date());
        sku.setUpdateTime(new Date());
        String code = this.generateSkuCode(selectors, dto.getSpuId());
        sku.setCode(code);
        sku.setCategoryId(spu.getCategoryId());
        sku.setRootCategoryId(spu.getRootCategoryId());
        sku.setSpecs(JSONUtil.toJsonStr(specs));
        this.save(sku);

        // 插入sku_specs
        this.insertSpecs(specs, dto.getSpuId(), sku.getId());
    }

    public void update(SkuDto dto, Long id) {
        Sku sku = this.getById(id);
        if(sku == null) {
            throw new CustomException("sku不存在");
        }

        Spu spu = spuService.getById(dto.getSpuId());
        if(spu == null) {
            throw new CustomException("商品不存在");
        }

        List<SkuSelector> selectors = dto.getSelectors();
        List<SpecKeyValue> specs = this.checkSelectors(selectors);
        if (specs == null) {
            throw new CustomException("规格选择错误");
        }

        BeanUtils.copyProperties(dto, sku);
        String code = this.generateSkuCode(selectors, dto.getSpuId());
        sku.setCode(code);
        sku.setCategoryId(spu.getCategoryId());
        sku.setRootCategoryId(spu.getRootCategoryId());
        sku.setSpecs(JSONUtil.toJsonStr(specs));
        sku.setUpdateTime(new Date());
        this.updateById(sku);

        // 3.先删除关联信息，再存储信息到关联表中
        skuSpecService.deleteSpecs(sku.getSpuId(), sku.getId());
        this.insertSpecs(specs, dto.getSpuId(), sku.getId());
    }


    private void insertSpecs(List<SpecKeyValue> specs, Long spuId, Long skuId) {
        ArrayList<SkuSpec> skuSpecList = new ArrayList<>();
        specs.forEach(spec -> {
            SkuSpec skuSpec = new SkuSpec();
            skuSpec.setSpuId(spuId);
            skuSpec.setSkuId(skuId);
            skuSpec.setKeyId(spec.getKeyId());
            skuSpec.setValueId(spec.getValueId());
            skuSpecList.add(skuSpec);
        });
        skuSpecService.saveBatch(skuSpecList);
    }

    private List<SpecKeyValue> checkSelectors(List<SkuSelector> selectors) {
        List<SpecKeyValue> specs = new ArrayList<>();
        for (SkuSelector selector : selectors) {
            SpecKeyValue specKeyAndValue = specValueService.getSpecKeyValue(selector.getKeyId(), selector.getValueId());
            if (specKeyAndValue == null) {
                return null;
            }
            specs.add(specKeyAndValue);
        }
        return specs;
    }

    public void delete(Long id) {
        // 删除 sku
        Sku sku = this.getById(id);
        if (sku == null) {
            throw new CustomException("sku不存在");
        }
        this.removeById(id);

        // 删除 sku_spec
        skuSpecService.deleteSpecs(sku.getSpuId(), sku.getId());
    }

    public List<Sku> getSkuListByIds(List<Long> ids) {
        return this.list(new QueryWrapper<Sku>().in("id", ids));
    }


    private SkuVo toVo(Sku sku) {
        SkuVo vo = new SkuVo();
        BeanUtils.copyProperties(sku, vo);

        Spu spu = spuService.getById(sku.getSpuId());
        vo.setSpuTitle(spu.getTitle());

        return vo;
    }

    private String generateSkuCode(List<SkuSelector> selectors, Long spuId) {
        // 调整：sku的code 调整成$分隔spu和sku，#分隔sku片段
        selectors.sort((o1, o2) -> (int) (o1.getKeyId() - o2.getKeyId()));
        StringBuilder builder = new StringBuilder();
        builder.append(spuId);
        builder.append("$");
        for (int i = 0; i < selectors.size(); i++) {
            SkuSelector skuSelector = selectors.get(i);
            builder.append(skuSelector.getKeyId());
            builder.append("-");
            builder.append(skuSelector.getValueId());
            if (i < selectors.size() - 1) {
                builder.append("#");
            }
        }
        // blob law
        return builder.toString();
    }
}
